package com.autumn.config.services.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.autumn.config.api.consts.ConfigureConsts.ConnectionTypeConsts;
import com.autumn.config.api.consts.ConfigureConsts.StatusConsts;
import com.autumn.config.api.dto.input.ConnectionConfigureInput;
import com.autumn.config.api.dto.input.NameQueryInput;
import com.autumn.config.api.dto.input.StatusInput;
import com.autumn.config.api.dto.output.ConnectionConfigureOutput;
import com.autumn.config.api.services.ICacheService;
import com.autumn.config.api.services.IConnectionConfigureService;
import com.autumn.config.entities.ApplicationInfo;
import com.autumn.config.entities.ApplicationProfileConnection;
import com.autumn.config.entities.ConnectionConfigure;
import com.autumn.config.entities.view.ServiceConnectionConfigureView;
import com.autumn.config.entities.view.ServiceDataSourceConfigureView;
import com.autumn.config.repositories.IApplicationInfoRepository;
import com.autumn.config.repositories.IApplicationProfileConnectionRepository;
import com.autumn.config.repositories.view.IServiceConnectionConfigureViewRepository;
import com.autumn.config.repositories.view.IServiceDataSourceConfigureViewRepository;
import com.autumn.mybatis.criterion.LockModeEnum;
import com.autumn.mybatis.criterion.Query;
import com.autumn.util.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 连接配置服务实现
 *
 * @author 老码农
 * <p>
 * Description
 * </p>
 * @date 2017-12-31 00:21:00
 */
@Service(interfaceClass = IConnectionConfigureService.class)
@Component
public class ConnectionConfigureServiceImpl extends
        AbstractConfigurePageService<ConnectionConfigure, ConnectionConfigure, ConnectionConfigureInput, ConnectionConfigureInput, ConnectionConfigureOutput, ConnectionConfigureOutput>
        implements IConnectionConfigureService {

    @Autowired
    private ICacheService cacheService;

    @Autowired
    private IServiceConnectionConfigureViewRepository serviceConfigureViewRepository;

    @Autowired
    private IServiceDataSourceConfigureViewRepository serviceDataSourceConfigureViewRepository;

    @Autowired
    private IApplicationProfileConnectionRepository refRepository;

    @Autowired
    private IApplicationInfoRepository appRepository;

    private void checkInput(ConnectionConfigureInput input) {
        ExceptionUtils.checkNotNull(input, "input");
        if (StringUtils.isNullOrBlank(input.getName())) {
            ExceptionUtils.throwValidationException("连接名称不能为空。");
        }
        if (StringUtils.isNullOrBlank(input.getPropertyContent())) {
            ExceptionUtils.throwValidationException("连接属性内容不能为空。");
        }
        if (ConnectionTypeConsts.getName(input.getConnectionType()) == null) {
            ExceptionUtils.throwValidationException("无效的连接类型");
        }
        AutumnContextUtils.parseProperties(input.getPropertyContent(), false);
    }

    private final static String NAME_FILED = "name";

    @Override
    @Transactional(rollbackFor = DataRollbackException.class)
    public ConnectionConfigureOutput add(ConnectionConfigureInput input) {
        checkInput(input);
        if (this.exist(NAME_FILED, input.getName())) {
            ExceptionUtils.throwValidationException(String.format("连接名称 %s 已重复。", input.getName()));
        }
        ConnectionConfigure configure = AutoMapUtils.map(input, ConnectionConfigure.class);
        if (configure.getSortId() == null) {
            configure.setSortId(1);
        }
        configure.insertAuditingInitialize();
        configure.setStatus(StatusConsts.STATUS_DRAFT);
        repository.insert(configure);
        return AutoMapUtils.map(configure, ConnectionConfigureOutput.class);
    }

    /**
     * 删除服务缓存
     *
     * @param connectionId 连接id
     */
    private void deleteServiceCacheInfo(Long connectionId) {
        if (connectionId == null) {
            return;
        }
        Set<String> serviceSet = new HashSet<>();
        Query query = new Query(ServiceConnectionConfigureView.class);
        query.eq("connectionId", connectionId).orderBy("id");
        List<ServiceConnectionConfigureView> items1 = serviceConfigureViewRepository.selectList(query.builderSection());
        for (ServiceConnectionConfigureView item : items1) {
            serviceSet.add(item.getServiceId());
        }
        query = new Query(ServiceDataSourceConfigureView.class);
        query.eq("connectionId", connectionId).orderBy("id");
        List<ServiceDataSourceConfigureView> items2 = serviceDataSourceConfigureViewRepository
                .selectList(query.builderSection());
        for (ServiceDataSourceConfigureView item : items2) {
            serviceSet.add(item.getServiceId());
            serviceSet.add(item.getTargetServiceId());
        }
        List<ApplicationProfileConnection> profileRefList = getProfileRefList(connectionId);
        Set<Long> appIdSet = new HashSet<>();
        if (profileRefList != null && profileRefList.size() > 0) {
            for (ApplicationProfileConnection app : profileRefList) {
                appIdSet.add(app.getAppId());
            }
        }
        for (Long appId : appIdSet) {
            ApplicationInfo appInfo = appRepository.get(appId);
            if (appInfo != null) {
                serviceSet.add(appInfo.getAppId());
            }
        }
        for (String serviceId : serviceSet) {
            cacheService.deleteServiceInfo(serviceId);
        }
    }

    @Override
    @Transactional(rollbackFor = DataRollbackException.class)
    public ConnectionConfigureOutput modify(ConnectionConfigureInput input) {
        checkInput(input);
        if (input.getId() == null) {
            ExceptionUtils.throwValidationException("Id 不能为空");
        }
        ConnectionConfigure result = this.getQueryById(input.getId(), LockModeEnum.UPDATE);
        if (result == null) {
            ExceptionUtils.throwValidationException(String.format("连接名称 %s 的配置不存在。", input.getName()));
        }
        if (result.getStatus().equals(StatusConsts.STATUS_RELEASE)) {
            ExceptionUtils.throwValidationException(String.format("连接名称 %s 为发布状态，不能修改。", input.getName()));
        }
        if (!input.getName().equalsIgnoreCase(result.getName())) {
            checkProfileRef(result.getId(), result.getName());
            if (this.exist(NAME_FILED, input.getName())) {
                ExceptionUtils.throwValidationException(String.format("连接名称 %s 已重复。", input.getName()));
            }
        }
        AutoMapUtils.map(input, result);
        result.updateAuditing();
        result.setStatus(StatusConsts.STATUS_DRAFT);
        repository.update(result);
        return AutoMapUtils.map(result, ConnectionConfigureOutput.class);
    }

    private void checkProfileRef(Long connectionId, String connectionName) {
        List<ApplicationProfileConnection> profileRefList = getProfileRefList(connectionId);
        if (profileRefList != null && profileRefList.size() > 0) {
            ApplicationProfileConnection profileRef = profileRefList.get(0);
            if (profileRef != null) {
                ApplicationInfo appInfo = appRepository.get(profileRef.getAppId());
                if (appInfo != null && !appInfo.getIsDelete()) {
                    ExceptionUtils.throwValidationException(String.format("连接名称 %s 已被应用 %s (%s) 的配置引用，不能修改名称、删除等操作。",
                            connectionName, appInfo.getAppId(), appInfo.getAppName()));
                }
            }
        }
    }

    private List<ApplicationProfileConnection> getProfileRefList(Long connectionId) {
        Query query = new Query(ApplicationProfileConnection.class);
        query.eq("connectionId", connectionId).orderBy("id");
        List<ApplicationProfileConnection> profileRefList = refRepository.selectList(query.builderSection());
        return profileRefList;
    }

    @Override
    @Transactional(rollbackFor = DataRollbackException.class)
    public ConnectionConfigureOutput updateStatus(StatusInput input) {
        ConnectionConfigureOutput result = super.updateStatus(input);
        if (result != null) {
            cacheService.deleteConnectionInfo(result.getName());
            deleteServiceCacheInfo(result.getId());
        }
        return result;
    }

    @Override
    protected ConnectionConfigure deleteById(Long id) {
        ConnectionConfigure result = super.deleteById(id);
        if (result != null) {
            checkProfileRef(result.getId(), result.getName());
            cacheService.deleteConnectionInfo(result.getName());
            deleteServiceCacheInfo(result.getId());
        }
        return result;
    }

    @Override
    public ConnectionConfigureOutput queryByName(NameQueryInput input) {
        ExceptionUtils.checkNotNull(input, "input");
        if (input.getName() == null) {
            ExceptionUtils.throwValidationException("连接名称不能为空。");
        }
        return cacheService.getConnectionInfo(input.getName(), (n) -> {
            Query query = new Query(ConnectionConfigure.class);
            query.eq("name", n).eq("isDelete", false).eq("status", StatusConsts.STATUS_RELEASE);
            return AutoMapUtils.map(this.repository.selectFirst(query.builderSection()),
                    ConnectionConfigureOutput.class);
        });
    }

}
